package com.yewen.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yewen.http.service.EducationCounselorService;
import com.yewen.websocket.handler.MessageHandler;
import com.yewen.websocket.message.Message;
import com.yewen.websocket.util.WebSocketUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

//{
//        type:"SEND_TO_ONE_Message",
//        body:{
//        toUser:"番茄",
//        msgId:"eaef4a3c-35dd-46ee-b548-f9c4eb6396fe",
//        content:"我是一条单聊消息"
//        }
//}

/**
 * @Classname WebSocketServerEndPoint
 * @Description
 * @Date 2022/3/25 17:22
 * @Created by TaoVh
 */
@Controller
@ServerEndpoint("/ws")
public class WebSocketServerEndPoint implements InitializingBean {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private EducationCounselorService educationCounselorService;
    /**
     * 消息类型与messagehandler的映射
     */
    private static final Map<String, MessageHandler> HANDLERS = new HashMap<>();

    @Autowired
    private ApplicationContext applicationContext;

    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        logger.info("[onOpen][session({}) 接入]", session);
        String userID = session.getRequestParameterMap().get("userID").get(0);
        String token = session.getRequestParameterMap().get("token").get(0);
        WebSocketUtil.addSession(session, userID);
    }

    @OnMessage
    public void onMessage(Session session, String message) {
        logger.debug("[onOpen][session({}) 接收到一条消息({})]", session, message); // 生产环境下，请设置成 debug 级别
        JSONObject messageJson = JSONObject.parseObject(message);
        /*获得消息类型*/
        String type = messageJson.getString("type");
        /*获得消息处理器*/
        MessageHandler messageHandler = HANDLERS.get(type);
        if (messageHandler == null) {
            logger.error("[onMessage][消息类型({}) 不存在消息处理器]", type);
            return;
        }
        /*解析消息*/
        Class<? extends Message> messageClass = this.getMessageClass(messageHandler);
        /*处理消息*/
        Message messageObj = JSON.parseObject(messageJson.getString("body"), messageClass);
        messageHandler.execute(session, messageObj);
    }

    private Class<? extends Message> getMessageClass(MessageHandler messageHandler) {
        // 获得 Bean 对应的 Class 类名。因为有可能被 AOP 代理过。
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(messageHandler);
        // 获得接口的 Type 数组
        Type[] interfaces = targetClass.getGenericInterfaces();
        Class<?> superclass = targetClass.getSuperclass();
        while ((Objects.isNull(interfaces) || 0 == interfaces.length) && Objects.nonNull(superclass)) { // 此处，是以父类的接口为准
            interfaces = superclass.getGenericInterfaces();
            superclass = targetClass.getSuperclass();
        }
        if (Objects.nonNull(interfaces)) {
            // 遍历 interfaces 数组
            for (Type type : interfaces) {
                // 要求 type 是泛型参数
                if (type instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    // 要求是 MessageHandler 接口
                    if (Objects.equals(parameterizedType.getRawType(), MessageHandler.class)) {
                        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                        // 取首个元素
                        if (Objects.nonNull(actualTypeArguments) && actualTypeArguments.length > 0) {
                            return (Class<Message>) actualTypeArguments[0];
                        } else {
                            throw new IllegalStateException(String.format("类型(%s) 获得不到消息类型", messageHandler));
                        }
                    }
                }
            }
        }
        throw new IllegalStateException(String.format("类型(%s) 获得不到消息类型", messageHandler));
    }


    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        WebSocketUtil.removeSession(session);
        logger.info("[onClose][session({}) 连接关闭。关闭原因是({})}]", session, closeReason);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        logger.info("[onClose][session({}) 发生异常]", session, throwable);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        /*通过applicationContext获取所有的MessageHandler Bean*/
        applicationContext.getBeansOfType(MessageHandler.class).values()
                .forEach((messageHandler -> HANDLERS.put(messageHandler.getType(), messageHandler)));
        logger.info("[afterPropertiesSet][消息处理器数量：{}]", HANDLERS.size());
    }


}
